/************************************************************************************** 
    WFActivity

    Copyright (C) 2010 =OsDevD=

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 **************************************************************************************
 */
package ez.workflow.activity;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import ez.math.graph.Vertex;
import ez.workflow.process.WFProcess;
import ez.workflow.process.WFProcessManager;
import ez.workflow.task.WFTask;
import ez.workflow.transition.WFTransitionLink;

/**
 * 
 * @author OsDevD
 * 
 *         WFActivity is one of the main class that is required to represent
 *         Workflow Process. Each Workflow Process can have one or more
 *         WFActivities linked with each other through WFLinks. Each WFLink can
 *         have multiple WFTransitions based on different conditions. Conditions
 *         will be explained later. In run-time Workflow Engine is running
 *         multiple WFProcesses. Basically for every WFProcessTemplate there is
 *         run-time equivalent that is called WFProcess. Business Workflow can
 *         be created using static representation of Workflow that is
 *         WFProcessTemplate that will be converted in run-time to WFProcess. At
 *         the same time all WFTemplateActivity that are the static
 *         representations of WFActivity will be converted in Run-time to
 *         WFActivity and WFTask. WFTask are individual task,work, job that are
 *         assigned to Resource like Principal, User or System. The definition
 *         is very flexible just because we have to think about how we can easy
 *         change current design in the future in order to support High
 *         performance/Low Latency/Multi user usage of iWorkflow-Engine Library
 *         as a core engine for Workflow Management and overall for Business
 *         Workflow Development.
 */
public class WFActivity extends Vertex implements WFActivityI {

	static final long serialVersionUID = 1L;

	private int activityId;
	private String activityName;
	public String activityType;

	public enum states {
		STARTED, TERMINATED, COMPLETED
	};

	public String state;

	private Map incomingWFTransitionLinkMap = null;
	private Map outcomingWFTransitionLinkMap = null;

	private final Map successorWFActivityMap;
	private final Map predeccessorWFActivityMap;

	private WFProcess process;
	private ArrayList<WFTask> WFTasks; // list of the WFTasks associated to
	// current
	// WFActivity
	private ArrayList WFFacts; // list of the WFFacts associated to current

	// WFActivity

	public WFActivity(Map incomingWFTransitionLinkMap,
			Map outcomingWFTransitionLinkMap, ArrayList wFTasks,
			ArrayList wFFacts) {
		super();
		this.incomingWFTransitionLinkMap = incomingWFTransitionLinkMap;
		this.outcomingWFTransitionLinkMap = outcomingWFTransitionLinkMap;

		this.successorWFActivityMap = new LinkedHashMap();
		this.predeccessorWFActivityMap = new LinkedHashMap();

		WFTasks = wFTasks;
		WFFacts = wFFacts;
	}

	public WFActivity(WFProcess process) {

		this.successorWFActivityMap = new LinkedHashMap();
		this.predeccessorWFActivityMap = new LinkedHashMap();

	}

	public WFActivity(String block) {
		WFActivityBlock(block);
		this.incomingWFTransitionLinkMap = incomingWFTransitionLinkMap;
		this.outcomingWFTransitionLinkMap = outcomingWFTransitionLinkMap;

		this.successorWFActivityMap = new LinkedHashMap();
		this.predeccessorWFActivityMap = new LinkedHashMap();

	}

	public void WFActivityBlock(String block) {
		if (block.equals("andBlock")) {
			// need implement the logic for handling AND Block transitions
			// namely have to wait until all Activities before AND block are
			// executed

			activityType = "AND-BLOCK";
		} else if (block.equals("orBlock")) {
			// at least one predecessor activity is executed
			activityType = "OR-BLOCK";
		} else if (block.equals("groundBlock")) {
			activityType = "GROUND-BLOCK";
		} else if (block.equals("conditionBlock")) {
			// continue the exectuion based on defined conditions
			activityType = "CONDITION-BLOCK";
		} else {
			// general purpose activity with tasks
			activityType = "ACTIVITY-BLOCK";
		}

	}

	public final void addSuccessorWFActivity(WFTransitionLink transitionLink,
			WFActivityI wfActivity) {
		this.successorWFActivityMap.put(transitionLink, wfActivity);
	}

	public final void addPredeccessorWFActivity(
			WFTransitionLink wfTransitionLink, WFActivityI wfActivity) {
		this.predeccessorWFActivityMap.put(wfTransitionLink, wfActivity);
	}

	public WFProcess getProcess() {
		return process;
	}

	public void setProcess(WFProcess process) {
		this.process = process;
	}

	public Map getIncomingWFTransitionLinkMap() {
		return incomingWFTransitionLinkMap;
	}

	public Map getOutcomingWFTransitionLinkMap() {
		return outcomingWFTransitionLinkMap;
	}

	public void setIncomingWFTransitionLinkMap(Map incomingWFTransitionLinkMap) {
		this.incomingWFTransitionLinkMap = incomingWFTransitionLinkMap;
	}

	public void setOutcomingWFTransitionLinkMap(Map outcmingWFTransitionLinkMap) {
		this.outcomingWFTransitionLinkMap = outcomingWFTransitionLinkMap;
	}

	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return super.hashCode();
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return super.toString();
	}

	public ArrayList getWFTasks() {
		return WFTasks;
	}

	public void setWFTasks(ArrayList wFTasks) {
		WFTasks = wFTasks;
	}

	public ArrayList getWFFacts() {
		return WFFacts;
	}

	public void setWFFacts(ArrayList wFFacts) {
		WFFacts = wFFacts;
	}

	@Override
	public WFTransitionLink execute() {
		// TODO Auto-generated method stub
		WFTransitionLink decision = null;
		// Put Task in the WFTaskQueue
		WFProcessManager processManager = getWorkflowProcess()
				.getProcessManager();
		if (processManager != null) {
			if (this.activityType.equals(WFActivityI.ACTIVITYBLOCK))

				// getting the list of the tasks
				for (WFTask task : this.WFTasks)

					// if Tasks is started - put then to the taskQueue for
					// execution
					// Probably need to have some sort of scheduling for
					// execution
					// multi threading
					if (task.isStarted()) {
						processManager.getTaskHandleQueue().add((WFTask) task);
						decision = task.getExecutionTransitionResult();
					}
			// start all tasks, so need to get the tasks list
		} else if (this.activityType.equals(WFActivityI.ANDBLOCK)) {
			// get all incoming transitions and predecessor activities
			boolean allActivitiesCompleted;
			Iterator iterator = this.getIncomingWFTransitionLinkMap().values().iterator();
			while(iterator.hasNext()) {
				WFTransitionLink transitionLink = (WFTransitionLink)iterator.next();
				if (!transitionLink.getStartWFActivity().isCompleted())
					allActivitiesCompleted = false;

			}
			

		} else if (this.activityType.equals(WFActivityI.ORBLOCK)) {

		} else if (this.activityType.equals(WFActivityI.GROUNDBLOCK)) {

		} else if (this.activityType.equals(WFActivityI.CONDITIONBLOCK)){
			
		}

			// 
		
		return decision;

	}

	@Override
	public Principal getActor() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Collection getAvailableIncomingWFTransitionLinks() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Collection getAvailableOutcomingWFTransitionLinks() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getDecisionStatus() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Date getEndTime() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List getErrors() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object[] getMessageArguments() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getMessageKey() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public WFActivityI getPredeccessorWFActivity(
			WFTransitionLink incomingWFTrannsitionLink) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Date getStartTime() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public WFActivityI getSuccessorWFActivity(
			WFTransitionLink outcomingWFTransitionLink) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public WFProcess getWorkflowProcess() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isCompleted() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isStarted() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub

		// when we start WFActivity we need to spawn the tasks from Activity
		// each Activity can have multiple tasks, so we need to start each of
		// the task
		// get the list of the tasks and start all of them
		for (WFTask task : this.WFTasks) {
			if (!task.isStarted()) {
				task.start();
				// when we start the task we need to put them to the waiting
				// queue
				// for execution
			}
		}

		// mark Activity that it is already started
		// this.state = (String)states.STARTED;

	}

	public void terminate() {

	}

	public void resume() {

	}

	public void suspend() {

	}

	public int getActivityId() {
		return activityId;
	}

	public void setActivityId(int activityId) {
		this.activityId = activityId;
	}

	public String getActivityName() {
		return activityName;
	}

	public void setActivityName(String activityName) {
		this.activityName = activityName;
	}

}
